#ifndef MYSOCKET_H
#define MYSOCKET_H

#include <cstdio>
#include <cstdlib>
#include <string>

#if defined _WIN32

    #include <winsock2.h>
    #include <ws2tcpip.h>

#else

    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <sys/time.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>

#endif


class MySocket
{
    private :
	
    #if defined __unix__
        int m_socket;
    #elif defined _WIN32
        SOCKET m_socket;
        static int m_nb;
    #endif  
    
    int *m_cloneNbr;
    
    /**
     * Constructeur de socket déja initialisée.
     */
    #if defined __unix__
        MySocket(int sock);
    #elif defined _WIN32
        MySocket(SOCKET sock);
    #endif
	
    public :
	
    /**
     * Constructeur, envoie une exception en cas d'échec de création de la socket.
     */
    MySocket();
    
    /**
     * Constructeur de copie;
     */
    MySocket(const MySocket& socket);
	
    /**
     * Destructeur.
     */
    ~MySocket();
	
    /**
     * Lit et met dans le buffer buf les len premier caractères depuis la socket.
     * @param buf le buffer
     * @param len le nombre maximum d'octets à lire
     * @param timeOutValue le temps maximum d'écoute de la socket avant abandon, 30sec par default, une valeur inférieur ou égale a 0 conduit a attendre indéfiniment.
     *
     * @return le nombre d'octets lu ou 0 si aucune donnée n'a pu être lue
     */
    int read(void* buf, int len, long timeOutValue = -1);
	
    /**
     * Ecrit les len premiers octets du buffer buf dans la socket, envoie une exception si une erreur c'est produite lors de l'ecriture ou si la fin du timeout à été atteinte sans pouvoir écrire
     * @param buf le buffer
     * @param len le nombre d'octets à ecrire
     * @param timeOutValue le temps maximum d'écoute de la socket avant abandon, 30sec par default, une valeur inférieur ou égale a 0 conduit a attendre indéfiniment.
     * @return le nombre d'octets envoyés
     */
    int write(const void *buf, int len, long timeOutValue = -1);
    
    /**
     * Assigne la socket à un port, envoie une exception en cas d'échec.
     * @param service le port ou le nom de service à utiliser.
     */
    void myBind(const char *service);
    
    /**
     * Place la socket en attente de connection, envoie une exception en cas d'échec.
     * @param nbConnectionMax le nombre maximum de client pouvant être mis en attente.
     */
    void myListen(int nbConnectionMax);
    
    /**
     * Essaie de se connecter à un serveur, envoie une exception en cas d'échec.
     * @param serverName le nom ou l'adresse du serveur.
     * @param service le port ou le nom de service à utiliser.
     */
    void myConnect(const char* serverName, const char* service);

    /**
     * Accepte la connexion d'un client.
     * @param addr sert à renvoyer les informations de connection du client, laisser null pour ne pas utiliser
     * @param addrlen la longueur de l'adresse du client (taille de la struct sockaddr)
     * @param timeOutValue le delai à attendre avant d'abandonner la connection.
     * 
     * @return la socket utilisée pour la communication entre le client et le serveur 
     */
    MySocket myAccept(struct sockaddr *addr, socklen_t *addrlen, long timeOutValue = -1);
};

#endif // MYSOCKET_H
